package com.twu.biblioteca;

import com.twu.biblioteca.domain.Book;
import com.twu.biblioteca.domain.MenuItem;
import com.twu.biblioteca.domain.Movie;
import com.twu.biblioteca.domain.User;

import java.util.InputMismatchException;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;
import static com.twu.biblioteca.util.ConsoleUtil.readInt;
import static com.twu.biblioteca.util.ConsoleUtil.readLine;
import static com.twu.biblioteca.util.ConsoleUtil.show;
import static java.lang.String.format;

public class Biblioteca {

    public static final List<MenuItem> MENU_ITEMS = newArrayList(
            new MenuItem(1, "View Book List"),
            new MenuItem(2, "Reserve Book"),
            new MenuItem(3, "Check Membership"),
            new MenuItem(4, "View Movie List"),
            new MenuItem(0, "Exit"));

    public static final List<Book> BOOKS = newArrayList(
            new Book(1, "Test-Driven Development by Example", 1),
            new Book(2, "Refactoring: Improving the Design of Existing Code", 1),
            new Book(3, "Head First Java", 1),
            new Book(4, "ABC", 1));

    public static final List<Movie> MOVIES = newArrayList(
            new Movie("Sholay", "1975", "Ramesh Sippy", "N/A"),
            new Movie("Titanic", "1997", "James Cameron", "8.9"),
            new Movie("Avatar", "2009", "James Cameron", "8.7"),
            new Movie("The Dark Knight", "2008", "Christopher Nolan", "8.8"),
            new Movie("V for Vendetta", "2005", "James McTeigue", "XXX"),
            new Movie("Life of Pi", "2012", "Ang Lee", "9.0"),
            new Movie("Kung Fu Panda 2", "2011", "Jennifer Yuh", "8.1"),
            new Movie("3 Idiots", "2009", "Rajkumar Hirani", "9.1"));

    public static final List<User> USERS = newArrayList(
            new User("111-1111", "admin", "Superman", "superman@gmail.com", "88888888888"),
            new User("111-1112", "foo", "Foo", "foo@gmail.com", "77777777777"),
            new User("111-1113", "bar", "Bar", "bar@gmail.com", "66666666666"));

    private static final int MENU_BOOK_LIST = 1;

    private static final int MENU_RESERVE_BOOK = 2;

    private static final int MENU_CHECK_DETAIL = 3;

    private static final int MENU_MOVIE_LIST = 4;

    private User currentUser;

    public void welcome() {
        show("Welcome to Biblioteca!\n");
    }

    public void showMenu() {
        show(format("You can choose an menu option:\n" +
                "########### Menu #############\n%s##############################\n\n",
                generateMenu(MENU_ITEMS)));
    }

    public void waitForSelectMenuOption() {
        Integer menuIndex;
        while (true) {
            show("Please choose a menu option:");
            try {
                menuIndex = readInt(System.in);
            } catch (InputMismatchException e) {
                show("Invalid input!!\n");
                continue;
            }

            if (menuIndex == 0) {
                show("Thank you for using!");
                break;
            }
            executeMenuByIndex(menuIndex);
        }
    }

    public void executeMenuByIndex(Integer menuIndex) {
        switch (menuIndex) {
            case MENU_BOOK_LIST:
                show(format("########## Book List #########\n%s##############################\n\n",
                        generateBookList(BOOKS)));
                break;

            case MENU_RESERVE_BOOK:
                if (userAuthenticate()) {
                    show("Input the book name:");
                    reserveBook(readLine(System.in));
                }
                break;

            case MENU_CHECK_DETAIL:
                if (userAuthenticate()) {
                    show(format("Name:%s\nEmail:%s\nPhone:%s\n",
                            currentUser.getName(),
                            currentUser.getEmailAddress(),
                            currentUser.getPhone()));
                } else {
                    show("Please talk to a Librarian. Thank you.\n");
                }
                break;

            case MENU_MOVIE_LIST:
                show(format("%-20s%-7s%-20s%-4s\n%s\n\n",
                        "Movie", "Year", "Director", "Rating", generateMoiveList(MOVIES)));
                break;

            default:
                show("Select a valid option!!\n");
                break;
        }
    }

    private boolean userAuthenticate() {
        return currentUser != null || login();
    }

    private boolean login() {
        show("Username:");
        String userName = readLine(System.in);
        show("Password:");
        String password = readLine(System.in);
        for (User user : USERS) {
            if (user.getUserName().equals(userName) && user.getPassword().equals(password)) {
                currentUser = user;
                return true;
            }
        }
        show("Login failed!\n");
        return false;
    }

    private void reserveBook(final String bookName) {
        for (Book book : BOOKS) {
            Integer amount = book.getAmount();
            if (book.getBookName().equals(bookName) && amount > 0) {
                book.setAmount(amount - 1);
                show("Thank You! Enjoy the book.\n");
                return;
            }
        }
        show("Sorry we don't have that book yet.\n");
    }

    private String generateBookList(List<Book> books) {
        StringBuilder bookList = new StringBuilder();
        for (Book book : books) {
            bookList.append(format("#%2d %s\n", book.getId(), book.getBookName()));
        }
        return bookList.toString();
    }

    private String generateMenu(List<MenuItem> menuItems) {
        StringBuilder menu = new StringBuilder();

        for (MenuItem menuItem : menuItems) {
            menu.append(format("#%2d %s\n", menuItem.getId(), menuItem.getItem()));
        }
        return menu.toString();
    }

    private String generateMoiveList(List<Movie> movies) {
        StringBuilder movieList = new StringBuilder();
        for (Movie movie : movies) {
            movieList.append(format("%-20s%-7s%-20s%-4s\n",
                    movie.getTitle(),
                    movie.getYear(),
                    movie.getDirector(),
                    movie.getRating()));
        }
        return movieList.toString();
    }
}
